package com.kexio.auth.mybatis;

import java.time.LocalDateTime;

import org.apache.ibatis.reflection.MetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.kexio.auth.config.SecurityProperties;
import com.kexio.auth.context.TenantContextHolder;
import com.kexio.auth.util.AuthContextUtils;

/**
 * MyBatis-Plus字段自动填充处理器
 * 
 * 基于MyBatis-Plus的FieldFill机制，自动填充实体的基础字段：
 * 1. 审计字段：创建人、创建时间、更新人、更新时间
 * 2. 租户字段：根据配置自动填充租户ID
 * 3. 软删除：初始化删除标记
 * 4. 版本控制：初始化版本号
 * 
 * 相比拦截器方式，此方案更轻量级，性能更好，推荐使用。
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
public class BaseFieldsMetaObjectHandler implements MetaObjectHandler {

    private static final Logger logger = LoggerFactory.getLogger(BaseFieldsMetaObjectHandler.class);

    @Autowired
    private SecurityProperties securityProperties;

    /**
     * 插入时自动填充字段
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        logger.debug("开始插入填充...");
        
        LocalDateTime now = LocalDateTime.now();
        String currentUserId = getCurrentUserId();
        String tenantId = getCurrentTenantId();

        // 填充创建时间 - 支持多种字段名
        this.fillIfExist(metaObject, "createTime", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "createDate", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "createdTime", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "createdDate", LocalDateTime.class, now);
        
        // 填充创建人 - 支持多种字段名
        if (currentUserId != null) {
            this.fillIfExist(metaObject, "createBy", String.class, currentUserId);
            this.fillIfExist(metaObject, "createUser", String.class, currentUserId);
            this.fillIfExist(metaObject, "createdBy", String.class, currentUserId);
            this.fillIfExist(metaObject, "creator", String.class, currentUserId);
        }
        
        // 填充更新时间 - 支持多种字段名
        this.fillIfExist(metaObject, "updateTime", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "updateDate", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "updatedTime", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "updatedDate", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "modifyTime", LocalDateTime.class, now);
        this.fillIfExist(metaObject, "modifyDate", LocalDateTime.class, now);
        
        // 填充更新人 - 支持多种字段名
        if (currentUserId != null) {
            this.fillIfExist(metaObject, "updateBy", String.class, currentUserId);
            this.fillIfExist(metaObject, "updateUser", String.class, currentUserId);
            this.fillIfExist(metaObject, "updatedBy", String.class, currentUserId);
            this.fillIfExist(metaObject, "modifier", String.class, currentUserId);
        }
        
        // 填充租户ID（仅当启用多租户时）
        if (securityProperties.getTenant().isEnabled() && StringUtils.hasText(tenantId)) {
            this.fillIfExist(metaObject, "tenantId", String.class, tenantId);
            this.fillIfExist(metaObject, "tenant", String.class, tenantId);
            logger.debug("填充租户ID: {}", tenantId);
        }
        
        // 填充删除标记 - 支持多种字段名
        this.fillIfExist(metaObject, "deleted", Integer.class, 0);
        this.fillIfExist(metaObject, "isDeleted", Integer.class, 0);
        this.fillIfExist(metaObject, "delFlag", Integer.class, 0);
        this.fillIfExist(metaObject, "status", Integer.class, 0);
        
        // 填充版本号
        this.fillIfExist(metaObject, "version", Long.class, 1L);

        logger.debug("插入填充完成: createTime={}, createBy={}, updateTime={}, updateBy={}, tenantId={}", 
                    now, currentUserId, now, currentUserId, tenantId);
    }

    /**
     * 更新时自动填充字段
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        logger.debug("开始更新填充...");
        
        LocalDateTime now = LocalDateTime.now();
        String currentUserId = getCurrentUserId();

        // 填充更新时间 - 支持多种字段名
        this.updateIfExist(metaObject, "updateTime", LocalDateTime.class, now);
        this.updateIfExist(metaObject, "updateDate", LocalDateTime.class, now);
        this.updateIfExist(metaObject, "updatedTime", LocalDateTime.class, now);
        this.updateIfExist(metaObject, "updatedDate", LocalDateTime.class, now);
        this.updateIfExist(metaObject, "modifyTime", LocalDateTime.class, now);
        this.updateIfExist(metaObject, "modifyDate", LocalDateTime.class, now);
        
        // 填充更新人 - 支持多种字段名
        if (currentUserId != null) {
            this.updateIfExist(metaObject, "updateBy", String.class, currentUserId);
            this.updateIfExist(metaObject, "updateUser", String.class, currentUserId);
            this.updateIfExist(metaObject, "updatedBy", String.class, currentUserId);
            this.updateIfExist(metaObject, "modifier", String.class, currentUserId);
        }

        logger.debug("更新填充完成: 时间={}, 操作人={}", now, currentUserId);
    }

    /**
     * 安全填充字段（仅当字段存在时）
     */
    private <T, E extends T> void fillIfExist(MetaObject metaObject, String fieldName, Class<T> fieldType, E fieldVal) {
        if (metaObject.hasSetter(fieldName)) {
            this.strictInsertFill(metaObject, fieldName, fieldType, fieldVal);
        }
    }
    
    /**
     * 安全更新字段（仅当字段存在时）
     */
    private <T, E extends T> void updateIfExist(MetaObject metaObject, String fieldName, Class<T> fieldType, E fieldVal) {
        if (metaObject.hasSetter(fieldName)) {
            this.strictUpdateFill(metaObject, fieldName, fieldType, fieldVal);
        }
    }

    /**
     * 获取当前用户ID
     */
    private String getCurrentUserId() {
        try {
            return AuthContextUtils.getCurrentUserId();
        } catch (Exception e) {
            logger.debug("获取当前用户ID失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取当前租户ID
     */
    private String getCurrentTenantId() {
        try {
            String tenantId = TenantContextHolder.getCurrentTenantId();
            
            // 如果没有租户上下文，但启用了租户模式，使用默认租户
            if (!StringUtils.hasText(tenantId) && securityProperties.getTenant().isEnabled()) {
                tenantId = "default";
                logger.debug("未找到当前租户ID，使用默认租户: {}", tenantId);
            }
            
            return tenantId;
        } catch (Exception e) {
            logger.debug("获取当前租户ID失败: {}", e.getMessage());
            
            // 如果启用了租户模式但获取失败，返回默认租户
            if (securityProperties.getTenant().isEnabled()) {
                return "default";
            }
            return null;
        }
    }
}
